#include <memory>
#include <signal.h>
#include <iostream>
#include "tcp_server.hpp"
#include "daemon.hpp"

void Usage(const char *proc)
{
    printf("\nUsage: %s port\n", proc);
}

Response calchelper(const Request &req)
{
    Response resp(0, 0);
    switch (req._op)
    {
    case '+':
        resp._ret = req._l + req._r;
        break;
    case '-':

        resp._ret = req._l - req._r;
        break;
    case '*':
        resp._ret = req._l * req._r;
        break;
    case '/':
        if (req._r == 0)
            resp._code = 1;
        else
            resp._ret = req._l / req._r;
        break;
    case '%':
        if (req._r == 0)
            resp._code = 2;
        else
            resp._ret = req._l % req._r;
        break;
    default:
        resp._code = 3;
        break;
    }
    return resp;
}

void *calculator(int sock)
{
    std::string inbuffer;
    while (true)
    {
        // 1.读取成功
        bool ret = Receive(sock, &inbuffer);
        if (!ret)
            break;
        // std::cout << inbuffer << std::endl;
        // 2.协议解析，得到一个完整的报文
        std::string package = Decode(inbuffer);
        if (package.empty())
            continue;
        // std::cout << package << std::endl;
        // std::cout << inbuffer << std::endl;
        LogMessage(NORMAL, "%s", package.c_str());
        // 3.反序列化，字节流->结构化数据
        Request req;
        req.Deserialize(package);
        // 4.业务逻辑
        Response resp = calchelper(req);
        // 5.序列化业务的处理结果
        std::string respstr = resp.Serialize();
        // std::cout << respstr << std::endl;
        // 6.添加长度信息，形成一个完成的报文
        respstr = Encode(respstr);
        // std::cout << respstr << std::endl;
        Send(sock, respstr);
    }
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        exit(1);
    }

    uint16_t port = atoi(argv[1]);
    // server在编写时要有较为严谨的判断逻辑
    // 一般服务器是要忽略SIGPIPE信号的，防止在运行过程中出现非法写入的问题
    std::unique_ptr<TcpServer> psvr(new TcpServer("0.0.0.0", port));
    psvr->AddService(calculator);
    Daemon();
    psvr->Start();
    return 0;
}